package webreg.model.swing;

import java.util.Vector;

import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import webreg.model.Athlet;
import webreg.model.Competition;
import webreg.model.Disciplin;
import webreg.model.exceptions.EmptyDescriptionException;
import webreg.model.exceptions.EmptyPlaceException;

/** Implementation for a competition
 * 
 * @author STKNOLL
 */
public class CompetitionTreeModel extends Competition implements TreeModel {
	private Vector<TreeModelListener> mListeners = new Vector<TreeModelListener>();
	

	/** Constructor for a competition
	 */
	public CompetitionTreeModel() {
		super();
	}

	/** Copy constructor
	 *
	 * @param toCopy The competition to copy
	 * @throws EmptyPlaceException 
	 * @throws EmptyDescriptionException 
	 */
	public CompetitionTreeModel(Competition toCopy) {
		super(toCopy);
		mListeners = new Vector<TreeModelListener>();		
	}


	/** Copy constructor
	 *
	 * @param toCopy The competition to copy
	 * @throws EmptyPlaceException 
	 * @throws EmptyDescriptionException 
	 */
	public CompetitionTreeModel(CompetitionTreeModel toCopy) throws EmptyDescriptionException, EmptyPlaceException {
		super(toCopy);
		mListeners = toCopy.mListeners;
	}
	
	/** Implementation of the compare function
	 * 
	 * @param toCompare The club used for comparison
	 * @return True if the clubs are equal, else false
	 */
	public boolean equals (CompetitionTreeModel toCompare) {
		return super.equals(toCompare);
	}

	public void addElementAt(TreePath wherePath, Object inObject) {
		System.out.println("Model: Tree.addElementAt wherePath: " + wherePath + " inObject:" + inObject);
		
		int[] childIndexes = null;
		Object[] childObjects = null;
	
		if ((inObject instanceof Athlet) && ( (wherePath.getLastPathComponent()) instanceof Competition ) ) {
			addElement( (Athlet)inObject );
			childObjects = new Object[1];
			childObjects[0] = inObject;
			childIndexes = new int[1];
			childIndexes[0] = (getAthlets().size() -1 );
		}
		else if ((inObject instanceof Disciplin) && ( (wherePath.getLastPathComponent()) instanceof Athlet ) ) {
			int index = addElement( (Athlet)wherePath.getLastPathComponent(), (Disciplin)inObject);
			if (index != -1 ) {
				childIndexes = new int[1];
				childIndexes[0] = (getAthlets().get(index).getDisciplins().size() - 1);			
				childObjects = new Object[1];
				childObjects[0] = inObject;
			}
		}
		else if ((inObject instanceof Athlet) && ( (wherePath.getLastPathComponent()) instanceof Athlet ) ) {
			// insert athlet before another one
			int index = addElement( (Athlet)wherePath.getLastPathComponent(), (Athlet)inObject);
			childObjects = new Object[1];
			childObjects[0] = inObject;
			childIndexes = new int[1];
			childIndexes[0] = index;			
		}
		else if ((inObject instanceof Disciplin) && ( (wherePath.getLastPathComponent()) instanceof Disciplin ) ) {
			// insert disciplin before another one
			int index = addElement( (Athlet)wherePath.getParentPath().getLastPathComponent(), (Disciplin)wherePath.getLastPathComponent(), (Disciplin)inObject);			
			childObjects = new Object[1];
			childObjects[0] = inObject;
			childIndexes = new int[1];
			childIndexes[0] = index;			
		}		
		else {
			System.out.println("Model: Do nothing for addElementAt(...) ");
			//TODO throw Exception here
			return;
		}
		System.out.println("Model: Call notify function. ");
		
        TreeModelEvent e = new TreeModelEvent(this, wherePath, childIndexes, childObjects);
        for (TreeModelListener tml : mListeners) {
            tml.treeNodesInserted(e);
            tml.treeStructureChanged( e );
        }
	}		
	
	public void removeElementAt(TreePath wherePath) {
		System.out.println("Model: Tree.removeElementAt wherePath: " + wherePath);
		
		int[] childIndexes = null;
		Object[] childObjects = null;
		TreePath parentPath = null;
	
		if ( wherePath.getLastPathComponent() instanceof Athlet ) {
			Athlet toRemove = (Athlet)wherePath.getLastPathComponent();
			parentPath = wherePath.getParentPath();
			int whereBefore = removeElement( toRemove );
			childObjects = new Object[1];
			childObjects[0] = toRemove;
			childIndexes = new int[1];
			childIndexes[0] = whereBefore;
		}
		else if ( wherePath.getLastPathComponent() instanceof Disciplin ) {
			parentPath = wherePath.getParentPath();
			Athlet toRemoveFrom = (Athlet)parentPath.getLastPathComponent();
			System.out.println("Remove from: " + toRemoveFrom);			
			Disciplin toRemove = (Disciplin)wherePath.getLastPathComponent();
			System.out.println("Remove: " + toRemove);			
			int index = removeElement( toRemoveFrom, toRemove );
			if (index != -1 ) {
				childIndexes = new int[1];
				childIndexes[0] = index;
				System.out.println("Remove index: " + index);
				childObjects = new Object[1];
				childObjects[0] = toRemove;			
			}
		}
		else {
			System.out.println("Model: Do nothing for removeElementAt(...) ");
			//TODO throw Exception here
			return;
		}
		System.out.println("Model: Call notify function. ");
		
        TreeModelEvent e = new TreeModelEvent(this, parentPath, childIndexes, childObjects);
        for (TreeModelListener tml : mListeners) {
            tml.treeNodesRemoved(e);
            tml.treeStructureChanged( e );
        }
	}
	
	
/* ########################## TreeModel Interface ##################################### */	
	
	@Override
	public void addTreeModelListener(TreeModelListener arg0) {
		System.out.println("Model: Add tree listener: " + arg0);
		mListeners.addElement(arg0);		
	}


	@Override
	public Object getChild(Object arg0, int arg1) {
		System.out.println("Model: getChild " + arg0.getClass().getName() + "  " + arg1);		
		if (arg0 instanceof Competition) {
			Athlet ath = ((Competition) arg0).getAthlets().get(arg1);
			return ath;
		}
		else if (arg0 instanceof Athlet) {
			Disciplin disc = ((Athlet) arg0).getDisciplins().get(arg1);	
			return disc;
		}
		System.out.println("Model: Ups return null for getChild");
		return null;
	}


	@Override
	public int getChildCount(Object arg0) {
		int size = 0;
		if (arg0 instanceof Competition) {
			size = ((Competition) arg0).getAthlets().size();
		}
		else if (arg0 instanceof Athlet) {
			size = ((Athlet) arg0).getDisciplins().size();
		}
		else {
			size = 0;
		}
		System.out.println("Model: getChildCount " + arg0.getClass().getName() + "   " + size);
		return size;
	}


	@Override
	public int getIndexOfChild(Object arg0, Object arg1) {
		System.out.println("Model: getIndexOfChild " + arg0 + "   arg1: " + arg1);		
		if (arg0 == null || arg1 == null) {
			System.out.println("Model: Ups, return -1");			
			return -1;
		}	
		if ( (arg0 instanceof Competition) && (arg1 instanceof Athlet)  ) {
			Competition comp = (Competition) arg0;
			Athlet toSearch = (Athlet) arg1;
			// find the position of the athlet
			for (int x = 0; x < comp.getAthlets().size(); x++ ) {
				Athlet ath1 = comp.getAthlets().get(x);
				if (ath1.equals(toSearch)) {
					System.out.println("Model: Found athlet at index: " + x);
					return x;
				}
			}
			return -1;		// athlet not in model
		}
		else if ( (arg0 instanceof Athlet) && (arg1 instanceof Disciplin)  ) {
			Athlet ath = (Athlet) arg0;
			Disciplin toSearch = (Disciplin) arg1;
			// find the position of the disciplin
			for (int x = 0; x < ath.getDisciplins().size(); x++ ) {
				Disciplin dis1 = ath.getDisciplins().get(x);
				if (dis1.equals(toSearch)) {
					System.out.println("Model: Found disciplin at index: " + x);					
					return x;
				}
			}
			return -1;
		}
		System.out.println("Model: Ups, return -1");
		return -1;
	}


	@Override
	public Object getRoot() {
		System.out.println("Model: getRoot " );		
		Competition treeRoot = null;
		treeRoot = new Competition( this );
		return treeRoot;
	}


	@Override
	public boolean isLeaf(Object arg0) {
		System.out.println("Model: isLeaf " + arg0);		
		if (arg0 instanceof Competition) {
			return false;
		}
		else if (arg0 instanceof Athlet) {
			return false;		
		}
		else if (arg0 instanceof Disciplin) {
			return true;
		}
		return false;
	}


	@Override
	public void removeTreeModelListener(TreeModelListener arg0) {
		System.out.println("Model: removeTreeModelListener");		
		mListeners.removeElement(arg0);		
	}


	@Override
	public void valueForPathChanged(TreePath arg0, Object arg1) {
		System.out.println("Model: valueForPathChanged");		
		// TODO Auto-generated method stub
		
	}

}
